package analyses;

import java.util.Vector;

public class ViewAnalyserGrid {
	boolean[][] grid;

	boolean[][] obstacles;
	
	int[][] allViews;
	
	// toDo: limit to Radus;
	
	public int[][] getAllViewAnalyse(boolean[][] obstacles) {
		allViews=new int[obstacles.length][obstacles[0].length];
		for (int x=0;x<obstacles.length;x++){
			for (int y=0;y<obstacles.length;y++){
				grid=getViewAnalyse(obstacles,x,y);
				for (int cX=0;cX<grid.length;cX++){
					for (int cY=0;cY<grid[x].length;cY++){
						if (grid[cX][cY])allViews[cX][cY]++;
					}
				}
			}
		}
		return allViews;
	}
	
	public int[][] getCompleteViewAnalyse(boolean[][] obstacles) {
		this.obstacles=obstacles;
		allViews=new int[obstacles.length][obstacles[0].length];
		grid = new boolean[obstacles.length][obstacles[0].length];
		for (int x=0;x<obstacles.length;x++){
			System.out.println("x: "+x);
			for (int y=0;y<obstacles[x].length;y++){
				this.stepView(x, y, 1, 0);
				this.stepView(x, y, -1, 0);
				this.stepView(x, y, 0, 1);
				this.stepView(x, y, 0, -1);
			}
		}
		return allViews;
	}
	
	
	int sumView;
	
	public boolean[][] getViewAnalyse(boolean[][] obstacles, int x, int y) {
		sumView=0;
		this.obstacles = obstacles;
		grid = new boolean[obstacles.length][obstacles[0].length];
		allViews=new int[obstacles.length][obstacles[0].length];
		this.stepView(x, y, 1, 0);
		this.stepView(x, y, -1, 0);
		this.stepView(x, y, 0, 1);
		this.stepView(x, y, 0, -1);
		return grid;
	}

	public void stepView(int x, int y, int stepX, int stepY) {

		int plusX;
		int plusY;
		
		Vector<ViewEvent> events = new Vector<ViewEvent>();

		if (stepX != 0) {
			ViewEvent newEvent = new ViewEvent(x, y, x + stepX, y - 1);
			events.add(newEvent);
			newEvent = new ViewEvent(x, y + 1, x + stepX, y + 2);
			events.add(newEvent);
			plusX = 0;
			plusY = 1;
		} else {
			ViewEvent newEvent = new ViewEvent(x, y, x - 1, y + stepY);
			events.add(newEvent);
			newEvent = new ViewEvent(x + 1, y, x + 2, y + stepY);
			events.add(newEvent);
			plusX = 1;
			plusY = 0;
		}

		Vector<ViewEvent> nextEvents = new Vector<ViewEvent>();
		while (events.size() > 0) {
			nextEvents = new Vector<ViewEvent>();

			for (int j = 0; j < events.size(); j++) {
				ViewEvent ev = events.get(j);
				ev.stepForward();
			}

			for (int i = 0; i < events.size(); i += 2) {
				ViewEvent cEvent0 = events.get(i);
				ViewEvent cEvent1 = events.get(i + 1);
				if (cEvent0.x != cEvent1.x || cEvent0.y != cEvent1.y) {
					int cX = cEvent0.x;
					int cY = cEvent0.y;
					boolean start = false;
					boolean value = this.get(cX, cY);
					if (value) {
						if (grid[cX][cY]!=true) sumView++;
						grid[cX][cY] = true;// entweder oder
						allViews[cX][cY]++;
						nextEvents.add(cEvent0);
						start = !start;
					}
					cX += plusX;
					cY += plusY;
					while (cX != cEvent1.x || cY != cEvent1.y) {
						value = this.get(cX, cY);
						if (value){
							if (grid[cX][cY]!=true) sumView++;
							grid[cX][cY] = true;// entweder oder
							allViews[cX][cY]++;
						}
						if (start != value) {
							nextEvents.add(new ViewEvent(cX, cY, cX + cX - x,
									cY + cY - y));
							start = !start;
						}
						cX += plusX;
						cY += plusY;
					}
					if (start) {
						nextEvents.add(cEvent1);
					}
				}
			}
			events = nextEvents;
		}
	}

	// Fehler bei einfacher Abstand

	// public void stepView2(int x, int y, int stepX, int stepY) {
	// int plusX;
	// int plusY;
	// Vector<ViewEvent> events = new Vector<ViewEvent>();
	//
	// if (stepX != 0) {
	// ViewEvent newEvent = new ViewEvent(x, y, x + stepX, y - 1);
	// events.add(newEvent);
	// newEvent = new ViewEvent(x, y, x + stepX, y + 1);
	// events.add(newEvent);
	// plusX = 0;
	// plusY = 1;
	// } else {
	// ViewEvent newEvent = new ViewEvent(x, y, x - 1, y + stepY);
	// events.add(newEvent);
	// newEvent = new ViewEvent(x, y, x + 1, y + stepY);
	// events.add(newEvent);
	// plusX = 1;
	// plusY = 0;
	// }
	//
	// boolean value0;
	// boolean value1;
	// boolean value2;
	// int x0, y0, x1, y1, x2, y2;
	// x1 = x;
	// y1 = y;
	//
	// Vector<ViewEvent> nextEvents = new Vector<ViewEvent>();
	// while (events.size() > 0) {
	// nextEvents = new Vector<ViewEvent>();
	// for (int j = 0; j < events.size(); j++) {
	// ViewEvent ev = events.get(j);
	// ev.stepForward();
	// }
	//
	// for (int i = 0; i < events.size(); i += 2) {
	// ViewEvent cEvent1 = events.get(i);
	// ViewEvent cEvent2 = events.get(i + 1);
	// x1 = cEvent1.x;
	// y1 = cEvent1.y;
	// x0 = x1 - plusX;
	// y0 = y1 - plusY;
	// x2 = x1 + plusX;
	// y2 = y1 + plusY;
	// value0 = this.get(x0, y0);
	// value1 = this.get(x1, y1);
	// value2 = this.get(x2, y2);
	//
	// if (value1) {
	// grid[x1][y1] = true;
	// nextEvents.add(cEvent1);
	// }
	// do {
	// if (value1) {
	// grid[x1][y1] = true;
	// if (!value0 && (x1 != cEvent1.x || y1 != cEvent1.y)) {
	// nextEvents.add(new ViewEvent(x1, y1, x1 + x1 - x,
	// y1 + y1 - y));// start
	// }
	// if (!value2 && (x1 != cEvent2.x || y1 != cEvent2.y)) {
	// nextEvents.add(new ViewEvent(x1, y1, x1 + x1 - x,
	// y1 + y1 - y));// start
	// }
	// }
	// x0 = x1;
	// y0 = y1;
	// x1 = x2;
	// y1 = y2;
	// x2 += plusX;
	// y2 += plusY;
	// value0 = value1;
	// value1 = value2;
	// value2 = this.get(x2, y2);
	// } while (x0 != cEvent2.x || y0 != cEvent2.y);
	// if (value0) {
	// grid[x0][y0] = true;
	// nextEvents.add(cEvent2);
	// }
	// }
	//
	// events = nextEvents;
	// }
	// }

	public boolean isInside(int x, int y) {

		if (x > obstacles.length - 1 || x < 0)
			return false;
		if (y > obstacles[0].length - 1 || y < 0)
			return false;
		return true;
	}

	public void drawLine(boolean[][] grid, int x1, int y1, int x2, int y2) {
		ViewEvent ev = new ViewEvent(x1, y1, x2, y2);
		while (ev.x != x2) {
			ev.stepForward();
			grid[ev.x][ev.y] = true;
		}
	}

	public boolean get(int x, int y) {
		if (x > obstacles.length - 1 || x < 0)
			return false;
		if (y > obstacles[x].length - 1 || y < 0)
			return false;
		return obstacles[x][y];
	}

	public class ViewEvent {
		int dFast;

		int dSlow;

		int x;

		int y;

		int stepPX;

		int stepPY;

		int stepDX;

		int stepDY;

		double cError;

		public ViewEvent(int startX, int startY, int endX, int endY) {
			int dX = endX - startX;
			int dY = endY - startY;
			int adX = Math.abs(dX);
			int adY = Math.abs(dY);
			stepDX = Integer.signum(dX);
			stepDY = Integer.signum(dY);

			if (adX > adY) {
				// x ist schnelle Richtung
				stepPX = stepDX;
				stepPY = 0;
				dFast = adY;
				dSlow = adX;
			} else {
				// y ist schnelle Richtung
				stepPX = 0;
				stepPY = stepDY;
				dFast = adX;
				dSlow = adY;
			}
			x = startX;
			y = startY;

			cError = dSlow / 2;
		}

		public void stepForward() {
			cError -= dFast;
			if (cError < 0) {
				cError += dSlow;
				x = x + stepDX;
				y = y + stepDY;
			} else {
				x = x + stepPX;
				y = y + stepPY;
			}
		}

	}

	public int getSumView() {
		return sumView;
	}
}
